home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1994…tember: Reference Library / Dev.CD Sep 94.toast / Periodicals / develop / develop Issue 6 / develop 6 code / TCP / NewsWatcher / NewsWatcher 2.0d15 source / source / search.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-08-01  |  7.0 KB  |  271 lines  |  [TEXT/KAHL]

  1. /*----------------------------------------------------------------------------
  2.  
  3.     search.c
  4.  
  5.     This module handles the "Search Selected Groups" command.
  6.     
  7.     Portions copyright © 1990, Apple Computer.
  8.     Portions copyright © 1993, Northwestern University.
  9.  
  10. ----------------------------------------------------------------------------*/
  11.  
  12. #include <string.h>
  13. #include <ctype.h>
  14. #include <stdio.h>
  15.  
  16. #include "dlgutil.h"
  17. #include "glob.h"
  18. #include "close.h"
  19. #include "mark.h"
  20. #include "menus.h"
  21. #include "nntp.h"
  22. #include "open.h"
  23. #include "popup.h"
  24. #include "resize.h"
  25. #include "search.h"
  26. #include "subscribe.h"
  27. #include "util.h"
  28.  
  29.  
  30.  
  31. #define kSearchDlg            140            /* Search dialog */
  32. #define kSearchHeader        3
  33. #define    kSearchPattern        4
  34. #define kSearchPopup        5
  35.  
  36.  
  37.  
  38. /*----------------------------------------------------------------------------
  39.     DoSearchDialog
  40.     
  41.     Presents the search dialog.
  42.             
  43.     Exit:    function result = true if OK clicked, false if Cancel clicked.
  44.             header = header name.
  45.             pattern = search string.
  46. ----------------------------------------------------------------------------*/
  47.  
  48. static Boolean DoSearchDialog (CStr255 header, CStr255 pattern)
  49. {
  50.     static CStr255 headerSave = "Subject";
  51.     static CStr255 patternSave = "";
  52.     DialogPtr dlg;
  53.     short item;
  54.     
  55.     dlg = MyGetNewDialog(kSearchDlg);
  56.     
  57.     strcpy(header, headerSave);
  58.     strcpy(pattern, patternSave);
  59.  
  60.     DlgSetCString(dlg, kSearchHeader, header);
  61.     SetItemMaxLength(dlg, kSearchHeader, 255);
  62.     DlgSetCString(dlg, kSearchPattern, pattern);
  63.     SetItemMaxLength(dlg, kSearchPattern, 255);
  64.     SelIText(dlg, kSearchPattern, 0, 255);
  65.     SetItemPopupTypeinItem(dlg, kSearchPopup, kSearchHeader);
  66.     
  67.     do {
  68.         DlgEnableItem(dlg, ok, *header != 0 && *pattern != 0);
  69.         MyModalDialog(DialogFilter, &item, true, true);
  70.         switch (item) {
  71.             case kSearchPopup:
  72.                 GetPopupCString(DlgGetControl(dlg, item), kCurrentPopupItem, header);
  73.                 DlgSetCString(dlg, kSearchHeader, header);
  74.                 SelIText(dlg, kSearchHeader, 0, 0x7fff);
  75.                 break;
  76.             case kSearchHeader:
  77.                 DlgGetCString(dlg, kSearchHeader, header);
  78.                 break;
  79.             case kSearchPattern:
  80.                 DlgGetCString(dlg, kSearchPattern, pattern);
  81.                 break;
  82.         }
  83.     } while (item != ok && item != cancel);
  84.     
  85.     MyDisposDialog(dlg);
  86.     
  87.     if (item == cancel) return false;
  88.     
  89.     strcpy(headerSave, header);
  90.     strcpy(patternSave, pattern);
  91.     return true;
  92. }
  93.  
  94.  
  95.  
  96. /*----------------------------------------------------------------------------
  97.     SearchOneGroup 
  98.     
  99.     Searches a single group.
  100.     
  101.     Entry:    header = name of the header to be searched.
  102.             pattern = search string.
  103.             *theGroup = group record.
  104.             
  105.     Exit:    function result = true if no error, false if error.
  106.             theGroup->numUnread = number of matched articles.
  107.             theGroup->unread = handle to unread list.
  108. ----------------------------------------------------------------------------*/
  109.  
  110. static Boolean SearchOneGroup (char *header, char *pattern, TGroup *theGroup)
  111. {
  112.     CStr255    groupName, statusStr;
  113.     short result;
  114.     THeader **headers = nil;
  115.     short numHeaders;
  116.     THeader *pHeader, *pHeaderEnd;
  117.     long firstUnread, lastUnread;
  118.     long number;
  119.  
  120.     strcpy(groupName, *gGroupNames + theGroup->nameOffset);
  121.  
  122.     strcpy(statusStr,"Searching group: ");
  123.     strcat(statusStr,groupName);
  124.     StatusWindow(statusStr);
  125.     
  126.     result = GetGroupArticleRange(theGroup);
  127.     if (result == 1) return true;
  128.     if (result == 2) return false;
  129.     
  130.     theGroup->numUnread = 0;
  131.     result = SearchHeaders(groupName, header, theGroup->firstMess,
  132.         theGroup->lastMess, pattern, &headers, &numHeaders);
  133.     if (result == 1) return true;
  134.     if (result == 2) return false;
  135.  
  136.     HLock((Handle)headers);
  137.     pHeaderEnd = *headers + numHeaders;
  138.     firstUnread = 0;
  139.     for (pHeader = *headers; pHeader < pHeaderEnd; pHeader++) {
  140.         number = pHeader->number;
  141.         if (firstUnread == 0) {
  142.             firstUnread = lastUnread = number;
  143.         } else if (pHeader->number == lastUnread+1) {
  144.             lastUnread = number;
  145.         } else {
  146.             AppendUnreadRange(firstUnread, lastUnread, theGroup);
  147.             firstUnread = lastUnread = number;
  148.         }
  149.     }
  150.     if (firstUnread != 0) AppendUnreadRange(firstUnread, lastUnread, theGroup);
  151.     MyDisposHandle((Handle)headers);
  152.     return true;
  153. }
  154.  
  155.  
  156.  
  157. /*----------------------------------------------------------------------------
  158.     SearchGroups
  159.     
  160.     Searches all the selected groups and builds a new group array containing
  161.     the matching groups and article lists.
  162.     
  163.     Entry:    wind = pointer to group window record.
  164.             header = header name.
  165.             pattern = search string.
  166.     
  167.     Exit:    function result = true if no error, false if error.
  168.             *newGroupArray = array of matching group records.
  169.             *newNumGroups = number of matching group records.
  170. ----------------------------------------------------------------------------*/
  171.  
  172. static Boolean SearchGroups (WindowPtr wind, char *header, char *pattern,
  173.     TGroup ***newGroupArray, short *newNumGroups)
  174. {
  175.     TWindow **info;
  176.     ListHandle theList;
  177.     Cell theCell;
  178.     short cellData, cellDataLen;
  179.     TGroup **groupArray;
  180.     TGroup theGroup; 
  181.     TGroup **theNewGroupArray = nil;
  182.     short theNewNumGroups;
  183.     short numAllocated;
  184.     short i;
  185.     TUnread **unread, **nextUnread;
  186.  
  187.     info = (TWindow**)GetWRefCon(wind);
  188.     theList = (**info).theList;
  189.     groupArray = (**info).groupArray;
  190.     theNewGroupArray = (TGroup**)MyNewHandle(100*sizeof(TGroup));
  191.     numAllocated = 100;
  192.     theNewNumGroups = 0;
  193.     SetPt(&theCell, 0, 0);
  194.     
  195.     while (LGetSelect(true, &theCell, theList)) {
  196.         cellDataLen = 2;
  197.         LGetCell(&cellData, &cellDataLen, theCell, theList);
  198.         theGroup.nameOffset = (*groupArray)[cellData].nameOffset;
  199.         theGroup.firstMess = theGroup.lastMess = theGroup.numUnread = 0;
  200.         theGroup.unread = nil;
  201.         theGroup.onlyRedrawCount = false;
  202.         if(!SearchOneGroup(header, pattern, &theGroup)) goto exit;
  203.         if (theGroup.numUnread != 0) {
  204.             if (theNewNumGroups >= numAllocated) {
  205.                 numAllocated += 100;
  206.                 MySetHandleSize((Handle)theNewGroupArray, numAllocated*sizeof(TGroup));
  207.             }
  208.             (*theNewGroupArray)[theNewNumGroups] = theGroup;
  209.             theNewNumGroups++;
  210.         }
  211.         theCell.v++;
  212.     }
  213.     
  214.     MySetHandleSize((Handle)theNewGroupArray, theNewNumGroups*sizeof(TGroup));
  215.     *newGroupArray = theNewGroupArray;
  216.     *newNumGroups = theNewNumGroups;
  217.     return true;
  218.     
  219. exit:
  220.  
  221.     for (i = 0; i < theNewNumGroups; i++) {
  222.         unread = (*theNewGroupArray)[i].unread;
  223.         while (unread != nil) {
  224.             nextUnread = (**unread).next;
  225.             MyDisposHandle((Handle)unread);
  226.             unread = nextUnread;
  227.         }
  228.     }
  229.     MyDisposHandle((Handle)theNewGroupArray);
  230.     return;
  231. }
  232.  
  233.  
  234.  
  235. /*----------------------------------------------------------------------------
  236.     DoSearch
  237.     
  238.     Handle the "Search Selected Groups" command.
  239.     
  240.     Entry:    wind = pointer to group window record.
  241. ----------------------------------------------------------------------------*/
  242.  
  243. void DoSearch (WindowPtr wind)
  244. {
  245.     CStr255    header,pattern;
  246.     TGroup **groupArray;
  247.     short numGroups;
  248.     WindowPtr newWind;
  249.     TWindow **info;
  250.     
  251.     /* Present the search dialog. */
  252.     
  253.     if (!DoSearchDialog(header, pattern)) return;
  254.     
  255.     /* Search the groups. */
  256.     
  257.     if (!SearchGroups (wind, header, pattern, &groupArray, &numGroups)) return;
  258.     if (numGroups == 0) {
  259.         ErrorMessage("No matching articles were found.");
  260.         return;
  261.     }
  262.     
  263.     /* Create the window. */
  264.     
  265.     newWind = NewUserGroupWindow("\pSearch Groups", groupArray, numGroups);
  266.     info = (TWindow**)GetWRefCon(newWind);
  267.     (**info).okToCloseIfChanged = true;
  268.     ShowWindow(newWind);
  269.     return;
  270. }
  271.